using System;
using System.Collections.Generic;
using System.Text;

namespace RS.DOM.Common
{
    public class LineCollection : List<Line>
    {
        #region Methods

        public virtual void Build()
        {
            foreach (Line line in this)
                line.Build();

            this.UnsplitLines();
        }

        public void UnsplitLines()
        {
            int i = 0;
            while (i < this.Count - 1)
            {
                if (this[i].LastToken != null)
                {
                    if (this[i].LastToken.BracketPriority > 1 ||
                        this[i].LastToken.SquareBracketPriority > 1)
                    {
                        this[i].AddRange(this[i + 1]);
                        this.RemoveAt(i + 1);

                        this[i].Build();
                    }
                    else
                    {
                        i++;
                    }
                }
            }
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            foreach (Line line in this)
                sb.Append(line.ToString() + "\r\n");

            return sb.ToString();
        }

        #endregion

        #region Properties

        public Line LastLine
        {
            get
            {
                if (this.Count > 0)
                    return this[this.Count - 1];
                else
                    return null;
            }
        }

        #endregion
    }

    public abstract class Line : List<Token>
    {
        #region Constructors

        public Line(Context context)
        {
            m_context = context;
        }

        #endregion

        #region Members

        private Context m_context;
        
        #endregion

        #region Properties

        public Context Context
        {
            get
            {
                return m_context;
            }

            set
            {
                m_context = value;
            }
        }

        public Token FirstToken
        {
            get
            {
                if (this.Count > 0)
                    return this[0];
                else
                    return null;
            }
        }

        public Token LastToken
        {
            get
            {
                if (this.Count > 0)
                    return this[this.Count - 1];
                else
                    return null;
            }
        }

        public object Result
        {
            get
            {
                if (this.LastToken != null)
                    return this.LastToken.Result;
                else
                    return "";
            }
        }

        #endregion

        #region Methods

        public Token BuildAndExecute()
        {
            this.Build();
            return this.Execute();
        }

        public abstract void Build();
        
        public abstract Token Execute();

        public void Add(Token token)
        {
            if (this.LastToken != null)
            {
                this.LastToken.NextToken = token;
                token.PrevToken = this.LastToken;
            }

            token.Context = this.Context;

            base.Add(token);
        }

        public void RemoveRange(int index, int count)
        {
            if (index == 0 && index + count < this.Count)
            {
                this[index + count].PrevToken = null;
            }
            else
            if (index + count == this.Count && index > 0)
            {
                this[index - 1].NextToken = null;
            }
            else
            if (index > 0 && index + count < this.Count)
            {
                this[index - 1].NextToken = this[index + count];
                this[index + count].PrevToken = this[index - 1];
            }

            base.RemoveRange(index, count);
        }

        public void Remove(Token token)
        {
            this.RemoveRange(this.IndexOf(token), 1);
        }

        public void Insert(int index, Token token)
        {
            if (index > 0)
            {
                token.PrevToken = this[index - 1];
                this[index - 1].NextToken = token;
            }

            if (index < this.Count)
            {
                token.PrevToken = this[index].PrevToken;
                token.NextToken = this[index];
                this[index].PrevToken = token;
            }

            token.Context = this.Context;

            base.Insert(index, token);
        }

        public void Replace(Line line, Token token)
        {
            int startIndex = this.IndexOf(line[0]);
            this.RemoveRange(startIndex, line.Count);
            this.Insert(startIndex, token);
        }

        public void Replace(Token token1, Token token2)
        {
            int startIndex = this.IndexOf(token1);
            this.RemoveRange(startIndex, 1);
            this.Insert(startIndex, token2);
        }

        public int IndexOf(string text)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].Text == text)
                    return i;

            return -1;
        }

        public Token GetOperation()
        {
            foreach (Token token in this)
            {
                if (token.TokenType == TokenType.Operator)
                    return token;
            }

            return null;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            foreach (Token token in this)
                sb.Append(token.ToString());

            return sb.ToString();
        }

        #endregion
    }
}
